﻿// 
//    Copyright 2010 The JaernCloud Project
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JaernCloud.Language.Compiler.Ast;
using JaernCloud.Language.Compiler.Types.Builtin;
using JaernCloud.Language.Compiler.Types.Builtin.View;
using JaernCloud.Language.Compiler.Types.Builtin.Model;
using JaernCloud.Language.Compiler.Types.Builtin.Page;

namespace JaernCloud.Language.Compiler.Types {
    
    /// <summary>
    /// Generates a typed node tree model based on an ast. The following nodes are built in:
    /// 
    ///     application
    ///     user
    ///     page
    ///     view
    ///     html, body, div, a, and all other nodes in the HTML 5 specification
    ///     css
    ///     js
    ///     json
    ///     xml
    ///     template
    /// 
    ///     model
    ///         integer
    ///         long
    ///         float
    ///         boolean
    ///         double
    ///     string
    ///         email
    ///         password
    ///         url
    ///         regex
    /// 
    ///     action (->)
    ///     validation
    ///     error
    ///     bundle
    /// </summary>
    public static class NodeTypeGenerator {
    
        private static readonly Dictionary<AstTag, NodeType> builtin = new Dictionary<AstTag,NodeType>();
        
        private static readonly IdentifierNodeType _identifier = new IdentifierNodeType();
        private static readonly ParameterNodeType _parameter = new ParameterNodeType();
        private static readonly ConstantNodeType _constant = new ConstantNodeType();
        private static readonly ActionNodeType _action = new ActionNodeType();
        private static readonly ExpressionNodeType _expression = new ExpressionNodeType();

        static void Register(NodeType nodeType) {
            builtin[nodeType.GetRequiredAstTag()] = nodeType;
        }

        static NodeTypeGenerator() {
           
            Register(new ApplicationNodeType());
            Register(new UserNodeType());
            Register(new PageNodeType());
            Register(new ViewNodeType());

            Register(new HTMLNodeType());
            Register(new BodyNodeType());
            Register(new HeadNodeType());
            Register(new TitleNodeType());
            Register(new DivNodeType());
            Register(new ParagraphNodeType());
            Register(new AnchorNodeType());
            // TODO: rest of html spec

            Register(new CSSNodeType());
            Register(new JSNodeType());
            Register(new JSONNodeType());
            Register(new XMLNodeType());
            Register(new TemplateNodeType());

            Register(new ModelNodeType());
            Register(new IntegerNodeType());
            Register(new LongNodeType());
            Register(new FloatNodeType());
            Register(new BooleanNodeType());
            Register(new DoubleNodeType());
            Register(new StringNodeType());
            Register(new EmailNodeType());
            Register(new PasswordNodeType());
            Register(new UrlNodeType());
            Register(new RegexNodeType());

            Register(new ValidationNodeType());
            Register(new ErrorNodeType());
            Register(new BundleNodeType());

        }

        public static INodeType GetBuiltInNodeType(AstTag tag) {
            
            if (tag.Name == "html") {
                // html has a head, title etc. It will be available as a child of RootNodeType
                return null;
            }
            
            // integer, double etc.

            NodeType nodeType;            
            if (builtin.TryGetValue(tag, out nodeType)) {
                return nodeType.GetNodeTypeInstanceFor(new AstNode() { Tag = AstTag.FromName(tag.Name) });
            }
            return null;
        }

        public static INodeType GetNodeTypeInstanceFor(AstNode node) {
            if (node.Constant != null) {
                return _constant.GetNodeTypeInstanceFor(node);
            }
            if (node.IsAction) {
                return _action.GetNodeTypeInstanceFor(node);
            }
            if (node.Expression != null) {
                return _expression.GetNodeTypeInstanceFor(node);
            }
            NodeType nodeType;
            if (node.Tag != null) {
                AstTag tag = AstTag.FromName(node.Tag.Name);
                if (builtin.TryGetValue(tag, out nodeType)) {
                    return nodeType.GetNodeTypeInstanceFor(node);
                }
            }
            return _identifier.GetNodeTypeInstanceFor(node);
        }

    }

}